package com.haoze.nurseapp.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.haoze.common.dto.PushSocketMessage;
import com.haoze.common.dto.SocketMessageDTO;
import com.haoze.common.response.Result;
import com.haoze.common.response.ResultGenerator;
import com.haoze.common.utils.DateUtil;
import com.haoze.common.utils.HttpClientUtil;
import com.haoze.common.utils.JSONUtils;
import com.haoze.common.utils.UUIDUtil;
import com.haoze.nurseapp.dao.NurseTeamDutyMapper;
import com.haoze.nurseapp.dao.NurseTeamMapper;
import com.haoze.nurseapp.dao.UserMapper;
import com.haoze.nurseapp.dto.*;
import com.haoze.nurseapp.model.NurseTeamDutyEntity;
import com.haoze.nurseapp.model.NurseTeamEntity;
import com.haoze.nurseapp.model.UserEntity;
import com.haoze.nurseapp.service.NurseTeamService;
import com.haoze.nurseapp.vo.NurseTeamDutyVo;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.regex.Pattern;

@Service
public class NurseTeamServiceImpl implements NurseTeamService {

    private static final Logger logger = LoggerFactory.getLogger(NurseTeamServiceImpl.class);

    @Autowired
    NurseTeamMapper nurseTeamMapper;

    @Autowired
    NurseTeamDutyMapper nurseTeamDutyMapper;

    @Resource
    UserMapper userMapper;

    @Autowired
    private MongoTemplate doctorMongoTemplate;

    @Value("${socket.url}")
    private String socketUrl;

    @Override
    public Result findPositionByUser() {
        String id = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()
                .getHeader("zuul_id");
        return ResultGenerator.genOkResult(nurseTeamMapper.findPositionByUser(id));
    }

    @Override
    public Result teamList(String wardDeptId) {
        return ResultGenerator.genOkResult(nurseTeamMapper.teamList(wardDeptId));
    }

    @Override
    public Result getListForInsert(String wardDeptId, String teamId) {
        Map<String, List<NurseTeamDutyVo>> map = new HashMap<>();
        map.put("nurseList", nurseTeamMapper.nurseList(wardDeptId, teamId));
        map.put("bedList", nurseTeamMapper.bedList(wardDeptId, teamId));
        map.put("teamName",nurseTeamMapper.teamName(teamId));
        return ResultGenerator.genOkResult(map);
    }

    @Override
    @Transactional
    public Result addOrUpdate(NurseTeamDutyVo nurseTeamDutyVo) {
        List<NurseTeamDutyEntity> list = new CopyOnWriteArrayList<>();
        if (StringUtils.isNotEmpty(nurseTeamDutyVo.getTeamId())) {
            NurseTeamEntity nurseTeamEntity = nurseTeamMapper.selectByPrimaryKey(nurseTeamDutyVo.getTeamId());
            nurseTeamEntity.initAdd();
            nurseTeamEntity.setModifyTime(new Date());
            nurseTeamEntity.setTeamName(nurseTeamDutyVo.getTeamName());
            nurseTeamMapper.updateByPrimaryKeySelective(nurseTeamEntity);
            nurseTeamDutyVo.getList().parallelStream().forEach(x -> {
                NurseTeamDutyEntity nurseTeamDutyEntity = new NurseTeamDutyEntity();
                nurseTeamDutyEntity.initAdd();
                nurseTeamDutyEntity.setBedNo(x.getBedNo());
                nurseTeamDutyEntity.setDutyId(UUIDUtil.randomString());
                nurseTeamDutyEntity.setIsHeader(x.getIsHeader());
                nurseTeamDutyEntity.setNurseId(x.getNurseId());
                nurseTeamDutyEntity.setNurseName(x.getNurseName());
                nurseTeamDutyEntity.setTeamId(nurseTeamEntity.getTeamId());
                nurseTeamDutyEntity.setTeamName(nurseTeamEntity.getTeamName());
                list.add(nurseTeamDutyEntity);
            });
            nurseTeamMapper.deleteTamDutyList(nurseTeamEntity.getTeamId());
            nurseTeamMapper.insertNurseTeamDutyEntity(list);
        } else {
            NurseTeamEntity nurseTeamEntity = new NurseTeamEntity();
            nurseTeamEntity.initAdd();
            nurseTeamEntity.setWardDeptId(nurseTeamDutyVo.getWardDeptId());
            nurseTeamEntity.setTeamName(nurseTeamDutyVo.getTeamName());
            nurseTeamEntity.setTeamId(UUIDUtil.randomString());
            nurseTeamEntity.setWardDeptName(nurseTeamDutyVo.getWardDeptName());
            nurseTeamMapper.insert(nurseTeamEntity);
            nurseTeamDutyVo.getList().parallelStream().forEach(x -> {
                NurseTeamDutyEntity nurseTeamDutyEntity = new NurseTeamDutyEntity();
                nurseTeamDutyEntity.initAdd();
                nurseTeamDutyEntity.setBedNo(x.getBedNo());
                nurseTeamDutyEntity.setDutyId(UUIDUtil.randomString());
                nurseTeamDutyEntity.setIsHeader(x.getIsHeader());
                nurseTeamDutyEntity.setNurseId(x.getNurseId());
                nurseTeamDutyEntity.setNurseName(x.getNurseName());
                nurseTeamDutyEntity.setTeamId(nurseTeamEntity.getTeamId());
                nurseTeamDutyEntity.setTeamName(nurseTeamEntity.getTeamName());
                list.add(nurseTeamDutyEntity);
            });
            nurseTeamMapper.insertNurseTeamDutyEntity(list);
        }
        return ResultGenerator.genOkResult();
    }

    @Override
    public Result deleteGroup(String teamId) {
        nurseTeamMapper.deleteTamList(teamId);
        nurseTeamMapper.deleteTamDutyList(teamId);
        return ResultGenerator.genOkResult();
    }

    @Override
    public Result queryMyPatientList(String type, String wardDeptId, int page, int pageSize, String searchValue) {
        String id = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()
                .getHeader("zuul_id");
        List<NurseTeamDutyVo> list = new ArrayList<>();
        PageHelper.startPage(page, pageSize);
        if (StringUtils.isNotEmpty(type) && "my".equalsIgnoreCase(type)) {
            list = nurseTeamMapper.queryPatientList(id, searchValue);
        } else if (StringUtils.isNotEmpty(type) && "all".equalsIgnoreCase(type)) {
            list = nurseTeamMapper.queryAllPatientList(id, wardDeptId, searchValue);
        }
        PageInfo<NurseTeamDutyVo> pageInfo = new PageInfo<>(list);
        return ResultGenerator.genOkResult(pageInfo);
    }

    @Override
    public Result queryMyPatientForDoctList(String type, String deptId, int page, int pageSize, String searchValue) {
        String id = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()
                .getHeader("zuul_id");
        List<NurseTeamDutyVo> list = new ArrayList<>();
        PageHelper.startPage(page, pageSize);
        if (StringUtils.isNotEmpty(type) && "my".equalsIgnoreCase(type)) {
            list = nurseTeamMapper.queryPatientForDoctList(id, searchValue);
        } else if (StringUtils.isNotEmpty(type) && "all".equalsIgnoreCase(type)) {
            list = nurseTeamMapper.queryAllPatientForDoctList(id, deptId, searchValue);
        }
        PageInfo<NurseTeamDutyVo> pageInfo = new PageInfo<>(list);
        return ResultGenerator.genOkResult(pageInfo);
    }

    @Override
    public Result queryMsgListByPatList(List<NurseTeamDutyVo> msgList) {
        String id = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()
                .getHeader("zuul_id");
        return queryMsg(msgList, id);
    }

    @Override
    public Result doAfterReadMsg(String inpatNum) {
        String id = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()
                .getHeader("zuul_id");
        Query query = new Query();
        query.addCriteria(Criteria.where("targetUser.userId").is(id));
        query.addCriteria(Criteria.where("patient.inpatNum").is(inpatNum));
        query.addCriteria(Criteria.where("isMsgRead").ne(true));
        Update update = new Update();
        update.set("isMsgRead", true);
        doctorMongoTemplate.updateMulti(query, update, Notification.class);
        return ResultGenerator.genOkResult();
    }

    @Override
    public Result transferMsg(Map<String, Object> notifications) {
        //发送给谁
        String sendUser = (String) notifications.get("sendUser");
        //谁发送的
        String sourceUser = (String) notifications.get("sourceUser");
        //发送内容
        //发送类型
        String type = (String) notifications.get("type");
        PushSocketMessage pushSocketMessage = new PushSocketMessage();
        SocketMessageDTO socketMessageDTO = new SocketMessageDTO();
        socketMessageDTO.setSender(sourceUser);
        socketMessageDTO.setData(notifications);
        socketMessageDTO.setReceiver(sendUser);
        socketMessageDTO.setMsgType(type);
        pushSocketMessage.setUserIds(new ArrayList<>(Arrays.asList(sendUser)));
        pushSocketMessage.setData(socketMessageDTO);
        logger.info("transferMsg接口调用socket入参：{}", JSONObject.toJSONString(pushSocketMessage));
        JSONObject json = HttpClientUtil.sendPost(socketUrl, pushSocketMessage);
        logger.info("transferMsg接口调用socket出参：{}", json);
        return ResultGenerator.genOkResult();
    }

    private Result queryMsg(List<NurseTeamDutyVo> list, String id) {
        list.parallelStream().forEach(x -> {
            Query query = new Query();
            query.addCriteria(Criteria.where("targetUser.userId").is(id));
            query.addCriteria(Criteria.where("patient.inpatNum").is(x.getInpatNum()));
            query.addCriteria(Criteria.where("isMsgRead").ne(true));
            long msgSize = doctorMongoTemplate.count(query, Notification.class);
            Query query2 = new Query();
            query2.addCriteria(Criteria.where("targetUser.userId").is(id));
            query2.addCriteria(Criteria.where("patient.inpatNum").is(x.getInpatNum()));
            query2.with(new Sort(Sort.Direction.DESC, "notifyDate")).limit(1);
            Notification notification = doctorMongoTemplate.findOne(query2, Notification.class);
            if (null != notification && null != notification.getType() && notification.getType().equals("CRITICAL")) {
                notification.setContent("危急值，请及时处理");
            }
            x.setNotification(notification);
            x.setUnReadMsgSize(msgSize);
        });
        return ResultGenerator.genOkResult(list);
    }

    @Override
    public Result queryPatientHistoryMsgList(String inpatNum, String type, int page, int pageSize, String searchValue, String searchStatus) {
        String id = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()
                .getHeader("zuul_id");
        Query query = new Query();
        query.addCriteria(Criteria.where("targetUser.userId").is(id));
        query.addCriteria(Criteria.where("patient.inpatNum").is(inpatNum));
        if (StringUtils.isNotEmpty(type) && type.equalsIgnoreCase("CRITICAL")) {
            query.addCriteria(Criteria.where("type").is(type));
            //危急值已处理/未处理
            if (StringUtils.isNotEmpty(searchStatus) && searchStatus.equals("1")) {
                query.addCriteria(Criteria.where("isRead").is(true));
            } else if (StringUtils.isNotEmpty(searchStatus) && searchStatus.equals("0")) {
                query.addCriteria(Criteria.where("isRead").is(false));
            }
        } else {
            query.addCriteria(Criteria.where("type").ne("CRITICAL"));
        }
        if (StringUtils.isNotEmpty(searchValue)) {
            Pattern pattern = Pattern.compile("^.*" + searchValue + ".*$", Pattern.CASE_INSENSITIVE);
            query.addCriteria(Criteria.where("content").regex(pattern));
        }
        long count = doctorMongoTemplate.count(query, Notification.class);
        query.with(new Sort(Sort.Direction.DESC, "notifyDate")).skip((page - 1) * pageSize).limit(pageSize);
        List<Notification> notifications = doctorMongoTemplate.find(query, Notification.class);
        List<MessageDTO> list = new CopyOnWriteArrayList<>();
        notifications.forEach(x -> {
            if (null != x.getType() && x.getType().equalsIgnoreCase("CRITICAL")) {
                //如果是危急值
                String patlabreportdataId = (String) JSONUtils.jsonToMap(x.getContent()).get("PATLABREPORTDATA_ID");
                if (StringUtils.isNotEmpty(patlabreportdataId)) {
                    Map<String, String> map = nurseTeamMapper.queryCriticalRecordStatusAndRes(patlabreportdataId);
                    if (null != map) {
                        x.setStatus(map.get("STATUS"));
                        x.setResult(map.get("RESULT"));
                        Map<String, Object> contentMap = JSONUtils.jsonToMap(x.getContent());
                        x.setContent(contentMap.get("LAB_REPORT_ITEM_CODE") + "," + contentMap.get("sepcimenCategory") + "," + contentMap.get("reportResult") + "," + contentMap.get("UNIT_ID") + "," + contentMap.get("REPORT_REMARK"));
                    }
                }
            }
            MessageDTO messageDTO = new MessageDTO();
            messageDTO.setMsgType(x.getContentType());
            messageDTO.setReceiver(x.getTargetUser().getUserId());
            messageDTO.setSender(null == x.getSourceUser() ? null : x.getSourceUser().getUserId());
            messageDTO.setSendDate(DateUtil.dateToString(x.getNotifyDate(), "yyyy-MM-dd HH:mm:ss"));
            messageDTO.setData(JSONUtils.jsonToMap(JSONUtils.beanToJson(x)));
            list.add(messageDTO);
//            AtomicBoolean isRead = new AtomicBoolean(false);
//            x.getReadUserList().forEach(y -> {
//                if(y.getUserId().equals(currentUser.getUserId()){
//                    isRead.set(true);
//                }
//            });
//            if(!isRead.get()){
//                ReadUser readUser = new ReadUser();
//                readUser.setReadDate(new Date());
//                readUser.setUserId(currentUser.getUserId());
//                readUser.setUserName(currentUser.getUserName());
//                x.getReadUserList().add(readUser);
//            }
        });
        PageInfo<MessageDTO> pageInfo = new PageInfo<>(list);
        pageInfo.setTotal(count);
        return ResultGenerator.genOkResult(pageInfo);
    }

    @Override
    public Result saveNurseStatus(String wardDeptId, String channle) {
        String id = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()
                .getHeader("zuul_id");
//        String id = "bf533ba10ec64ab0bbf360c44fa7a787";
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(id));
        query.addCriteria(Criteria.where("wardDeptId").is(wardDeptId));
        UserDept nurseDept = doctorMongoTemplate.findOne(query, UserDept.class);
        if (null == nurseDept) {
            nurseDept = new UserDept();
            nurseDept.setCreateDate(new Date());
            nurseDept.setUpdateDate(new Date());
            nurseDept.setUserId(id);
            nurseDept.setWardDeptId(wardDeptId);
            nurseDept.setChannle(StringUtils.isNotEmpty(channle) ? channle : "my");
            doctorMongoTemplate.save(nurseDept);
        } else {
            Update update = Update.update("updateDate", new Date()).set("wardDeptId",wardDeptId).set("channle",StringUtils.isNotEmpty(channle) ? channle : nurseDept.getChannle());
            doctorMongoTemplate.updateMulti(query, update, UserDept.class);
        }
        return ResultGenerator.genOkResult();
    }

    @Override
    public List<String> querySendUser(String inpatNum, String userType) {
        List<String> res = new CopyOnWriteArrayList();
        List<Map<String, String>> list;
        if ("nurse".equalsIgnoreCase(userType)) {
            //根据住院号查询该病区对应的分组护士，添加到发送用户集合A中
            //根据住院号查询该病区对应的所有护士
            list = nurseTeamMapper.queryAllNurseList(inpatNum);

        } else if ("doctor".equalsIgnoreCase(userType)) {
            //根据住院号查询床位医生，添加到发送用户集合A中
            //根据住院号查询该科室的所有医生
            list = nurseTeamMapper.queryAllDoctorList(inpatNum);
        } else {
            //查询病人的所有医生+护士
            list = nurseTeamMapper.queryAllUserList(inpatNum);
        }
        //循环科室医生，查询是否存在mongoDB，如果根据channle=all查询出了该医生，则把该护士添加到用户集合A中，添加前判断是否已经存在
        //循环病区护士，查询是否存在mongoDB，如果根据channle=all查询出了该护士，则把该护士添加到用户集合A中，添加前判断是否已经存在
        list.parallelStream().filter(x -> null != x.get("IS_GROUP") && "0".equals(x.get("IS_GROUP"))).map(x -> {
            Query query = new Query();
            query.addCriteria(Criteria.where("userId").is(x.get("USER_ID")));
            query.addCriteria(Criteria.where("wardDeptId").is(x.get("WARD_DEPT_ID")));
            UserDept userDept = doctorMongoTemplate.findOne(query, UserDept.class);
            if (null == userDept) {
                x.clear();
            } else if (null != userDept.getChannle() && "my".equalsIgnoreCase(userDept.getChannle())) {
                x.clear();
            }
            return x;
        });
        list.parallelStream().filter(x -> x.size() != 0).forEach(x -> {
            res.add(x.get("USER_ID"));
        });
        return res;
    }

    @Override
    public Result saveMessage(Map<String, Object> notifications) {
        String id = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()
                .getHeader("zuul_id");
        UserEntity currentUser = userMapper.selectByPrimaryKey(id);
        List<Notification> list = new CopyOnWriteArrayList<>();
        List<String> accountList = querySendUser((String) notifications.get("inpatNum"), "all");
        accountList.parallelStream().forEach(x -> {
            Notification notification = new Notification();
            PushSocketMessage pushSocketMessage = new PushSocketMessage();
            SocketMessageDTO socketMessageDTO = new SocketMessageDTO();
            notification.setContent((String) notifications.get("content"));
            notification.setType((String) notifications.get("type"));
            notification.setContentType((String) notifications.get("contentType"));
            notification.setNotifyDate(new Date());
            notification.setId(new ObjectId());
            notification.setNotificationId(UUIDUtil.randomString());
            notification.setNotifyLevel("2");
            notification.setIsMsgRead(false);
            TargetUser targetUser = new TargetUser();
            targetUser.setUserId(x);
            UserEntity userEntity = userMapper.selectByPrimaryKey(x);
            targetUser.setUserName(null == userEntity ? "" : userEntity.getUserName());
            if(StringUtils.isNotEmpty(id)) {
                SourceUser sourceUser = new SourceUser();
                sourceUser.setUserId(currentUser.getUserId());
                sourceUser.setUserName(currentUser.getUserName());
                notification.setSourceUser(sourceUser);
                socketMessageDTO.setSender(currentUser.getUserId());
            }
            Patient patient = new Patient();
            patient.setInpatNum((String) notifications.get("inpatNum"));
            notification.setTargetUser(targetUser);
            notification.setPatient(patient);
            notification.setRead(false);
            socketMessageDTO.setData(JSONUtils.jsonToMap(JSONUtils.beanToJson(notification)));
            socketMessageDTO.setReceiver(x);
            socketMessageDTO.setMsgType((String) notifications.get("contentType"));
            pushSocketMessage.setUserIds(new ArrayList<>(Arrays.asList(x)));
            pushSocketMessage.setData(socketMessageDTO);
            HttpClientUtil.sendPost(socketUrl, pushSocketMessage);
            list.add(notification);
        });
        doctorMongoTemplate.insertAll(list);
        return ResultGenerator.genOkResult();
    }

    @Override
    public String getUserId() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()
                .getHeader("zuul_id");
    }
}
